package nape.geom;
import nape.util.FastMath;
import nape.util.MixPool;
import nape.util.Names;
import nape.util.NpAlgorithm;
import nape.util.NpList;
import nape.geom.AABB;
import nape.geom.Axis;
import nape.geom.Mat23;
import nape.geom.VecMath;
import nape.Const;
import nape.util.NpNode_ZNContact;
import nape.util.NpAllocList_ZNContact;
import nape.util.NpNode_ZNV2;
import nape.util.NpList_ZNV2;
import nape.util.NpNode_Vec2__Dynamic;
import nape.util.NpList_Vec2__Dynamic;
import nape.util.NpNode_ZNShp;
import nape.util.NpList_ZNShp;

//'newfile' generated imports
import nape.util.NpNode_ZNV2;
import nape.util.NpList_ZNV2;
import nape.util.NpList_Vec2__Dynamic;










    class Vec2Iterator {
        
        
    static public var pool:Vec2Iterator;
    public var pool_next:Vec2Iterator;

    
        public var cur:NpNode_ZNV2;
    
        public function new() {}
        public static inline function get(list:NpList_ZNV2) {
            var ret =  {
    if(Vec2Iterator.pool==null) new Vec2Iterator();
    else {
        var ret = Vec2Iterator.pool;
        Vec2Iterator.pool = ret.pool_next;
        ret;
    }
};
            ret.cur = list.begin();
            return ret;
        }
        public inline function free() {
            cur = null;
        }
        
        public inline function hasNext():Bool {
            if(cur==null) {
                 {
    this.free();
    this.pool_next = Vec2Iterator.pool;
    Vec2Iterator.pool = this;
};
                return false;
            }else
                return true;
        }
        public inline function next():Vec2 {
            
            
            var _ret = cur.elem();
            cur = cur.next;
            return  _ret.wrapper();
        }
        
    }


    class MutableVec2List {
        public var znp_inner:ZNV2;

        public var znp_broadcast:Vec2->Void;
        public var znp_validate:Void->Void;
        public var length(get_length,never):Int;
        
        
        
        
        public function new(inner:ZNV2, broadcast:Vec2->Void, validate:Void->Void) {
            znp_inner = inner;
            znp_broadcast = broadcast;
            znp_validate = validate;
        }
        
        public inline function get_length() {
            znp_validate();
            return znp_inner.size();
        }
        
        public inline function at(i:Int) {            
            if(i<0||i>=length) return null;
            else {
                znp_validate();
                return  {
    var broad = znp_inner.at(length-1-i).outer==null;
    var ret = znp_inner.at(length-1-i).wrapper();
    if(broad)
        ret.znp_broadcast.add(znp_broadcast);
    
    ret;
};
            }
        }
        
        public inline function push(x:Vec2) {
            x.znp_broadcast.add(znp_broadcast);
            znp_inner.add( x.znp_inner);
            znp_broadcast(null);
        }
        
        public inline function pop() {
            znp_validate();
            var ret =  {
    var broad = znp_inner.pop_unsafe().outer==null;
    var ret = znp_inner.pop_unsafe().wrapper();
    if(broad)
        ret.znp_broadcast.add(znp_broadcast);
    
    ret;
};
            ret.znp_broadcast.remove(znp_broadcast);
            znp_broadcast(null);
            return ret;
        }
    }




class Vec2 {
    public var znp_inner:ZNV2;

    public var x(get_x,set_x):Float;
    public var y(get_y,set_y):Float;
    public inline function get_x() return znp_inner.x
    public inline function get_y() return znp_inner.y
    public inline function set_x(x:Float) {
        if(znp_inner.x!=x) {
            znp_inner.x = x;
              {
    var npiterator = znp_broadcast.begin();
    while(npiterator != null) {
        var i = npiterator.elem();
        {
            
            
            i(this);
        }
        npiterator = npiterator.next;
    }
};
        }
        return x;
    }
    public inline function set_y(y:Float) {
        if(znp_inner.y!=y) {
            znp_inner.y = y;
              {
    var npiterator = znp_broadcast.begin();
    while(npiterator != null) {
        var i = npiterator.elem();
        {
            
            
            i(this);
        }
        npiterator = npiterator.next;
    }
};
        }
        return y;
    }
    
    public inline function clone() return new Vec2(znp_inner.x,znp_inner.y)
    
    public var znp_broadcast:NpList_Vec2__Dynamic;
    
    public function new(x:Float, y:Float) {
        znp_inner = ZNV2.get(x,y);
        znp_inner.outer = this;
        znp_broadcast = new NpList_Vec2__Dynamic();
    }
    
    public var length(get_length,set_length):Float;
    public inline function get_length():Float {
        return  Math.sqrt(    (znp_inner.x*znp_inner.x + znp_inner.y*znp_inner.y));
    }
    
    public inline function set_length(length:Float) {
         {
    var d =     (znp_inner.x*znp_inner.x + znp_inner.y*znp_inner.y);
    var imag = if(d<Const.EPSILON) 0 else 1.0/Math.sqrt(d);
     { var t = (imag); znp_inner.x *= t; znp_inner.y *= t; };
};
         { var t = (length); znp_inner.x *= t; znp_inner.y *= t; };
        return length;
    }
    
    public var lsq(get_lsq,never):Float;
    public inline function get_lsq():Float {
        return     (znp_inner.x*znp_inner.x + znp_inner.y*znp_inner.y);
    }
    
    public inline function toString() return "{ x: "+znp_inner.x+" y: "+znp_inner.y+" }"
}



class ZNV2 {
    public var outer:Vec2;
    
    
    static public var pool:ZNV2;
    public var pool_next:ZNV2;

    public inline function free() {
        outer = null;
    }
    
    
    public var next:ZNV2;
    public inline function elem ():ZNV2 return this
    public inline function begin():ZNV2 return next 
    
    public inline function _setbeg(i:ZNV2) next=i
    public inline function _new   (o:ZNV2):ZNV2 return o
    public inline function _delete(i:ZNV2) {}
    public inline function _delelt(o:ZNV2) {}
    public inline function _clear ( ) return false
    
    
    
    public inline function add(o:ZNV2) {
        var temp = _new(o);
        temp.next = begin();
        _setbeg(temp);
    }
    
    
    public inline function addAll(x:ZNV2) {
           {
    var npiterator = x.begin();
    while(npiterator != null) {
        var i = npiterator.elem();
        {
            
            
            add(i);
        }
        npiterator = npiterator.next;
    }
};
    }
    
    
    public inline function insert(cur:ZNV2,o:ZNV2) {
        if(cur==null) { add(o); return begin(); }
        else {
            var temp = _new(o);
            temp.next = cur.next;
            cur.next = temp;
            return temp;
        }
    }
    
    
    
    
    public inline function pop():Void {
        var ret = begin();
        _setbeg(ret.next);
        _delelt(ret.elem());
        _delete(ret);
    }
    
    
    public inline function pop_unsafe():ZNV2 {
        var ret = front();
        pop();
        return ret;
    }
    
    
    
    
    public inline function remove(obj:ZNV2):Bool {
        var pre = null;
        var cur = begin();
        var ret = false;
        while(cur!=null) {
            if(cur.elem()==obj) {
                erase(pre,cur);
                ret = true;
                break;
            }
            pre = cur;
            cur = cur.next;
        }
        return ret;
    }
    
    
    public inline function erase(pre:ZNV2,cur:ZNV2):ZNV2 {
        var old = cur; cur = cur.next;
        if(pre==null) _setbeg(cur);
        else pre.next = cur;
        _delelt(old.elem());
        _delete(old);
        return cur;
    }
    
    
    public inline function splice(pre:ZNV2,cur:ZNV2,n:Int):ZNV2 {
        while(n-->0 && cur!=null) cur = erase(pre,cur);
        return cur;
    }
    
    
    public inline function clear() {
        if(_clear()) {
            while(!empty()) {
                var old = begin();
                _setbeg(old.next);
                _delelt(old.elem());
                _delete(old);
            }
        }
    }
    
    
    
    
    public inline function reverse() {
        var cur = begin();
        var pre = null;
        while(cur!=null) {
            var nx = cur.next;
            cur.next = pre;
            _setbeg(cur);
            pre = cur;
            cur = nx;
        }
    }
    
    
    
    
    public inline function empty():Bool return begin()==null
    
    
    public inline function size() {
        var cnt = 0;
        var cur = begin();
        while(cur!=null) { cnt++; cur = cur.next; }
        return cnt;
    }
    
    
    public inline function has(obj:ZNV2) return  ({
    var ret = false;
      {
    var npiterator = this.begin();
    while(npiterator != null) {
        var npite = npiterator.elem();
        {
            
            
            {
        if(npite==obj) {
            ret = true;
            break;
        }
    };
        }
        npiterator = npiterator.next;
    }
};
    ret;
})
    
    
    
    
    public inline function front() return begin().elem()
    
    
    public inline function back() {
        var ret = begin();
        var cur = ret;
        while(cur!=null) { ret = cur; cur = cur.next; }
        return ret.elem();
    }
    
    
    public inline function iterator_at(ind:Int) {
        var ret = begin();
        while(ind-->0 && ret!=null) ret = ret.next;
        return ret;
    }
    
    
    public inline function at(ind:Int) {
        var it = iterator_at(ind);
        return if(it!=null) it.elem() else null;
    }
    


     public var x:Float; public var y:Float;
    
    public function new() {}
    
    public inline function wrapper() {
        if(outer==null) {
            outer = new Vec2(x,y);
             {
    outer.znp_inner.free();
    outer.znp_inner.pool_next = ZNV2.pool;
    ZNV2.pool = outer.znp_inner;
};
            outer.znp_inner = this;
        }
        return outer;
    }
    
    public inline static function get(x:Float, y:Float) {
        var ret =  {
    if(ZNV2.pool==null) new ZNV2();
    else {
        var ret = ZNV2.pool;
        ZNV2.pool = ret.pool_next;
        ret;
    }
};
         { ret.x = x; ret.y = y; };
        return ret;
    }
    
    public inline function clone() {
        return get(x,y);
    }
    
    public inline function toString() return "{ x: "+x+" y: "+y+" }"
}
